// -----------------------------------------------------------------------
//  <copyright file="IdentityModule.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2022 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://www.dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2022-12-20 20:58</last-date>
// -----------------------------------------------------------------------

using System.ComponentModel;

using DaprPlus.Domain.Entity;
using DaprPlus.Identity.Application;
using DaprPlus.Identity.Domain.Entities;
using DaprPlus.Identity.Domain.Services;
using DaprPlus.Identity.Infrastructure.EntityFrameworkCore;
using Shares.Infrastructure;

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;

using OpenIddict.Validation.AspNetCore;


namespace DaprPlus.Identity.Infrastructure.Identity;

[Description("Identity Module")]
public class IdentityModule : IdentityModuleBase<User, Role>
{
    /// <summary>
    /// 获取 模块启动顺序，模块启动的顺序按级别启动，同一级别内部再按此顺序启动
    /// 级别默认为0，表示无依赖，需要在同级别有依赖顺序的时候，再重写为&gt;0的顺序值
    /// </summary>
    public override int Order => 3;

    /// <summary>
    /// 将模块服务添加到依赖注入服务容器中
    /// </summary>
    /// <param name="services">依赖注入服务容器</param>
    /// <returns></returns>
    public override IServiceCollection AddServices(IServiceCollection services)
    {
        services.AddEntityFrameworkCore();
        services.AddScoped<IDbContext>(provider => provider.GetRequiredService<IdentityDbContext>());

        services.AddMailKitEmailSender();
        services.AddCaptchaService();

        services.AddScoped<IUserStore<User>, UserStore>();
        services.AddScoped<IRoleStore<Role>, RoleStore>();

        services.AddScoped<IUserSyncService, UserSyncService>();
        services.AddScoped<IRoleSyncService, RoleSyncService>();

        services.Replace<IOnlineUserProvider, OnlineUserProvider<User, UserClaim, UserLogin, UserToken, Role, UserRole>>(ServiceLifetime.Singleton);

        services.AddDbContext<IdentityDbContext>((builder, options) =>
        {
            builder.UseSqlServer(options.ConnectionString, opt =>
            {
                opt.MigrationsAssembly(options.MigrationsAssembly ?? Assembly.GetName().Name);
            });

            // 注册OpenIddict所需的实体集。
            // 注意：如果需要替换默认OpenIddict实体，请使用泛型重载。
            builder.UseOpenIddict();
        });

        services.AddAuthentication(opts =>
            {
                opts.DefaultScheme = "JWT_OR_COOKIE";
                opts.DefaultChallengeScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
            })
            .AddPolicyScheme("JWT_OR_COOKIE", "JWT or Cookie", opts =>
            {
                opts.ForwardDefaultSelector = context =>
                {
                    // 如果是OAuth相关端点，使用Cookie认证
                    if (context.Request.Path.StartsWithSegments("/connect"))
                    {
                        return CookieAuthenticationDefaults.AuthenticationScheme;
                    }
                    if (context.Request.Headers.ContainsKey("Authorization"))
                    {
                        return OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
                    }
                    // 默认使用Cookie认证
                    return CookieAuthenticationDefaults.AuthenticationScheme;
                };
            })
            .AddCookie(opts =>
            {
                opts.LoginPath = new PathString("/login");
            });

        return base.AddServices(services);
    }

    /// <summary>
    /// 应用AspNetCore的服务业务
    /// </summary>
    /// <param name="app">Web应用程序</param>
    public override async Task UseModule(WebApplication app)
    {
        app.UseAuthentication();

        var provider = app.Services;
        provider.CheckAndMigration<IdentityDbContext>();
        await provider.CheckAndSeedAsync();
        await base.UseModule(app);
    }

    protected override void ConfigureIdentityBuilder(IServiceCollection services, IdentityBuilder builder)
    {
        builder.AddUserStore<UserStore>().AddRoleStore<RoleStore>();
        base.ConfigureIdentityBuilder(services, builder);
    }

    protected override void ConfigureOpenIddictCore(IServiceCollection services, OpenIddictCoreBuilder builder)
    {
        builder.UseEntityFrameworkCore().UseDbContext<IdentityDbContext>();
    }

}
